package practica1.ui.panelPoblacion;

import beancomentarios.JBeanComentarios;
import com.toedter.calendar.JCalendar;
import es.miguelgonzalez.jgraficacomida.GraficaComidaChangeEvent;
import es.miguelgonzalez.jgraficacomida.GraficaComidaChangeEventListener;
import es.miguelgonzalez.jgraficacomida.JGraficaComida;
import es.miguelgonzalez.jgraficacomida.JGraficaComidaModel;
import java.awt.BorderLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Calendar;
import javax.swing.*;
import practica1.language.Language;
import practica1.language.LanguageEvent;
import practica1.language.LanguageListener;
import practica1.logic.LogicPoblacion;
import practica1.logic.LogicPoblacionEvent;
import practica1.logic.LogicPoblacionListener;
import practica1.ui.simulacion.PanelSimulacionBacterias;
import practica1.ui.tablaPoblacion.ModeloPoblacionFactory;
import practica1.ui.tablaPoblacion.ModeloPoblacionTabla;
import practica1.ui.tablaPoblacion.TablaPoblacion;
import practica1.util.JTextFieldNumerico;

/**
 * Panel que muestra toda la información de una población
 * @author Miguel González - Ceura
 */
public class PanelPoblacion extends JPanel
        implements GraficaComidaChangeEventListener, LogicPoblacionListener,
        LanguageListener {
      
    //Propiedades del comidaPoblacionGrafica
    private JTabbedPane tabPaned;
    //Objetos de los componentes que se muestran
    private JGraficaComida comidaPoblacionGrafica;
    private JCalendar calendario;
    private JTextFieldNumerico txtTamanioPoblacion;
    private JTextFieldNumerico txtTemperatura;
    private JComboBox cboTemperatura;
    private ModeloComboBox modeloTemperatura;
    private JComboBox cboLuminosidad;
    private ModeloComboBox modeloLuminosidad;
    private JCheckBox chkSincronizarComida;
    private TablaPoblacion tablaPoblacion;
    private JBeanComentarios jbeanComentarios;
    //Paneles del tabPaned
    private JPanel panelDatosExperimento;
    private JPanel panelPoblacionExperimento;
    private JPanel panelComentarios;
    private PanelSimulacionBacterias panelSimulacion;
    
    private JLabel lblFechaComienzo;
    private JLabel lblTamanioPoblacion;
    private JLabel lblTemperatura;
    private JLabel lblLuminosidad;
    
    private EscuchadorLuminosidad escuchadorLuminosidad;
    private EscuchadorTemperatura escuchadorTemperatura;
    
    //Modelo de la población
    private LogicPoblacion modeloPoblacion;
    
    /**
     * Constructor del panel de la población
     * @param modeloPoblacion Recibe un modelo de la población sobre el cual
     * toma los datos
     */
    public PanelPoblacion(LogicPoblacion modeloPoblacion) {
        super();
        
        this.modeloPoblacion = modeloPoblacion;
        
        //Iniciamos el layout
        initLayout();
        
        //Inicializamos los componentes
        initComponents();
        
        //Añadimos los escuchadores
        initListeners();
    }
    
    /**
     * Inicializa los listeners de los componentes Swing
     */
    private void initListeners() {
        Language.getI().addLanguageListener(this);
        
        calendario.addPropertyChangeListener("calendar", new PropertyChangeListener() {
            @Override public void propertyChange(PropertyChangeEvent evt) {
                modeloPoblacion.setFecha( 
                        calendario.getCalendar().get(Calendar.DAY_OF_MONTH) +
                        "/" + calendario.getCalendar().get(Calendar.MONTH) + 
                        "/" + calendario.getCalendar().get(Calendar.YEAR));
            }
        });
        
        txtTamanioPoblacion.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {}
            @Override
            public void focusLost(FocusEvent e) {
                if(modeloPoblacion.getTamanioPoblacion() != 
                        Integer.parseInt(txtTamanioPoblacion.getText())) {
                    modeloPoblacion.setTamanioPoblacion(
                        Integer.parseInt(txtTamanioPoblacion.getText()));
                }
            }
        });
        
        txtTamanioPoblacion.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(modeloPoblacion.getTamanioPoblacion() != 
                        Integer.parseInt(txtTamanioPoblacion.getText())) {
                    modeloPoblacion.setTamanioPoblacion(
                        Integer.parseInt(txtTamanioPoblacion.getText()));
                }
            }
        });
        
        txtTemperatura.addFocusListener(new FocusListener() {
            @Override
            public void focusGained(FocusEvent e) {}
            @Override
            public void focusLost(FocusEvent e) {
                if(modeloPoblacion.getTemperatura() != 
                        Integer.parseInt(txtTemperatura.getText())) {
                    modeloPoblacion.setTemperatura(
                        Integer.parseInt(txtTemperatura.getText()));
                }
            }
        });
        
        txtTemperatura.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(modeloPoblacion.getTemperatura() != 
                        Integer.parseInt(txtTemperatura.getText())) {
                    modeloPoblacion.setTemperatura(
                        Integer.parseInt(txtTemperatura.getText()));
                }
            }
        });
        
        escuchadorTemperatura = new EscuchadorTemperatura();
        cboTemperatura.addItemListener(escuchadorTemperatura);
        
        escuchadorLuminosidad = new EscuchadorLuminosidad();
        cboLuminosidad.addItemListener(escuchadorLuminosidad);
        
        chkSincronizarComida.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if(modeloPoblacion.isSincronizarComida() !=
                        chkSincronizarComida.isSelected()) {
                    modeloPoblacion.setSincronizarComida(
                        chkSincronizarComida.isSelected());
                }
            }
        });
    }
    
    /**
     * Permite escuchar el cambio en el jcombobox de la luminosidad
     */
    private class EscuchadorLuminosidad implements ItemListener {
        @Override public void itemStateChanged(ItemEvent e) {
                if(!modeloPoblacion.getLuminosidad().equals(
                        (String)cboLuminosidad.getSelectedItem())) {
                    modeloPoblacion.setLuminosidad(
                        (String)cboLuminosidad.getSelectedItem());
                }
            }
    }
    
    /**
     * Permite escuchar el cambio en el jcombobox de la temperatura
     */
    private class EscuchadorTemperatura implements ItemListener {
        @Override public void itemStateChanged(ItemEvent e) {
            if(!modeloPoblacion.getEscalaTemperatura().equals(
                    (String)cboTemperatura.getSelectedItem())) {
                        modeloPoblacion.setEscalaTemperatura(
                        (String)cboTemperatura.getSelectedItem());
            }
        }
    }
    
    /**
     * Construye la interfaz gráfica
     */
    private void initLayout() {
        setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
        setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
        
        panelDatosExperimento = new JPanel();
        
        panelPoblacionExperimento = new JPanel();
        panelPoblacionExperimento.setLayout(new BorderLayout());
        
        panelComentarios = new JPanel();
        panelComentarios.setLayout(new BorderLayout());
        
        panelSimulacion = new PanelSimulacionBacterias(modeloPoblacion);
        
        tabPaned = new JTabbedPane();
        tabPaned.addTab(Language.getI().getP("DATOS_POBLACION")
                , null, panelDatosExperimento,
                        Language.getI().getP("DATOS_POBLACION"));
        tabPaned.setMnemonicAt(0, KeyEvent.VK_1);
        tabPaned.addTab(Language.getI().getP("POBLACION")
                , null, panelPoblacionExperimento, 
                Language.getI().getP("POBLACION"));
        tabPaned.setMnemonicAt(0, KeyEvent.VK_2);
        tabPaned.addTab(Language.getI().getP("COMENTARIOS")
                , null, panelComentarios,
                Language.getI().getP("COMENTARIOS"));
        tabPaned.setMnemonicAt(0, KeyEvent.VK_3);
        tabPaned.addTab(Language.getI().getP("SIMULACION")
                , null, panelSimulacion,
                Language.getI().getP("SIMULACION"));
        tabPaned.setMnemonicAt(0, KeyEvent.VK_4);
        
        //Agregamos los objetos al panel de los datos del comidaPoblacionGrafica
        JPanel panelDatos = new JPanel(new GridBagLayout());
        panelDatosExperimento.add(panelDatos);
        
        calendario = new JCalendar(Calendar.getInstance());
        txtTamanioPoblacion = new JTextFieldNumerico();
        
        
        txtTemperatura = new JTextFieldNumerico();
        
        modeloTemperatura = new ModeloComboBox(new String[]{
            Language.getI().getP("CENTIGRADOS"),
            Language.getI().getP("FARENHEIT")});
        
        cboTemperatura = new JComboBox(modeloTemperatura);
        
        modeloLuminosidad = new ModeloComboBox(new String[]{
            Language.getI().getP("ALTA"),
            Language.getI().getP("MEDIA"), 
            Language.getI().getP("BAJA")});
        cboLuminosidad = new JComboBox(modeloLuminosidad);
        
        
        lblFechaComienzo = new JLabel(
                Language.getI().getP("FECHA_COMIENZO_POBLACION"));
        lblTamanioPoblacion = new JLabel(
                Language.getI().getP("TAMANIO_POBLACION_INICIAL"));
        lblTemperatura = new JLabel(
                Language.getI().getP("TEMPERATURA"));
        lblLuminosidad = new JLabel(
                Language.getI().getP("CONDICIONES_LUMINOSIDAD"));
        
        lblTamanioPoblacion.setLabelFor(txtTamanioPoblacion);
        lblTemperatura.setLabelFor(txtTemperatura);
        lblLuminosidad.setLabelFor(cboLuminosidad);
        GridBagConstraints c = new GridBagConstraints();
        c.fill = GridBagConstraints.HORIZONTAL;
        c.gridx = 0;
        c.gridy = 0;
        panelDatos.add(lblFechaComienzo, c);
        c.gridx = 1;
        c.gridy = 0;
        c.gridwidth = 2;
        panelDatos.add(calendario, c);
        c.gridwidth = 1;
        c.gridx = 0;
        c.gridy = 1;
        panelDatos.add(lblTamanioPoblacion, c);
        c.gridx = 1;
        c.gridy = 1;
        c.gridwidth = 2;
        panelDatos.add(txtTamanioPoblacion, c);
        
        c.insets = new Insets(10,0,0,0);  //top padding
        c.gridwidth = 1;
        
        c.gridx = 0;
        c.gridy = 2;
        panelDatos.add(lblTemperatura, c);
        c.gridx = 1;
        c.gridy = 2;
        c.weightx = 1;
        panelDatos.add(txtTemperatura, c);
        c.weightx = 0;
        c.gridx = 2;
        c.gridy = 2;
        panelDatos.add(cboTemperatura, c);

        c.gridx = 0;
        c.gridy = 3;
        panelDatos.add(lblLuminosidad, c);
        c.gridx = 1;
        c.gridy = 3;
        c.gridwidth = 2;
        panelDatos.add(cboLuminosidad, c);
        
        //Añadimos a la ventana el tabPaned
        add(tabPaned);
    }
    
    /**
     * Inicializa los componentes respecto al modelo
     */
    private void initComponents() {
        //Iniciamos las propiedades de la población
        txtTamanioPoblacion.setText("" + modeloPoblacion.getTamanioPoblacion());
        txtTemperatura.setText("" + modeloPoblacion.getTemperatura());
        if(modeloPoblacion.getLuminosidad().isEmpty()) {
            cboLuminosidad.setSelectedIndex(0);
        } else {
            cboLuminosidad.setSelectedItem(
                    Language.getI().getT(modeloPoblacion.getLuminosidad()));
        }
        
        if(modeloPoblacion.getEscalaTemperatura().isEmpty()) {
            cboTemperatura.setSelectedIndex(0);
        } else {
            cboTemperatura.setSelectedItem(
                    Language.getI().getT(modeloPoblacion.getEscalaTemperatura()));
        }
        comidaPoblacionGrafica = new JGraficaComida(
                modeloPoblacion.getModeloGraficaComida());
        tablaPoblacion = new TablaPoblacion(
                modeloPoblacion.getModeloPoblacionTabla());
        
        String fecha = modeloPoblacion.getFecha();
        String fechaArray[] = fecha.split("/");
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, Integer.parseInt(fechaArray[2]));
        calendar.set(Calendar.MONTH, Integer.parseInt(fechaArray[1]));
        calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(fechaArray[0]));
        calendario.setCalendar(calendar);
        
        
        //Agregamos los objetos gráficos específicos
        JPanel panelExp = new JPanel();
        panelExp.setLayout(new BoxLayout(panelExp, BoxLayout.Y_AXIS));
        
        //Nos suscribimos a los cambios de la comida de la población
        modeloPoblacion.getModeloGraficaComida().addChangeEventListener(this);
        modeloPoblacion.addLogicPoblacionListener(this);
        //Guardamos el modelo del comidaPoblacionGrafica en las propiedades
        panelExp.add(this.comidaPoblacionGrafica);
        
        //Agregamos un checkbox para permitir decidir si sincronizar la comida
        JPanel panelCheckBox = new JPanel();
        chkSincronizarComida = new JCheckBox(
                Language.getI().getP("SINCRONIZAR_COMIDA_GRAFICA"),
                modeloPoblacion.isSincronizarComida());
        
        panelCheckBox.add(chkSincronizarComida);
        panelExp.add(panelCheckBox);
        
        //Agregamos el panel del comidaPoblacionGrafica al panel del tabPaned
        panelPoblacionExperimento.add(panelExp, BorderLayout.NORTH);
        panelPoblacionExperimento.add(new JScrollPane(this.tablaPoblacion),
                BorderLayout.CENTER);
        jbeanComentarios = new JBeanComentarios(modeloPoblacion.
                getModeloComentarios());
        panelComentarios.add(jbeanComentarios, BorderLayout.CENTER);
        
        if(Language.getI().getIdiomaCountry().equals("ES")) {
            jbeanComentarios.cambiarIdioma(JBeanComentarios.IDIOMA_E);
            comidaPoblacionGrafica.cambiarIdioma(JGraficaComida.IDIOMA_E);
        } else {
            jbeanComentarios.cambiarIdioma(JBeanComentarios.IDIOMA_I);
            comidaPoblacionGrafica.cambiarIdioma(JGraficaComida.IDIOMA_I);
        }
    }
   
    /**
     * Devuelve el modelo de la población sobre el cual se pinta el panel
     * @return ModeloPoblacion
     */
    public LogicPoblacion getPoblacion() {
        return modeloPoblacion;
    }
    
    /**
     * Método que es llamado cuando cambia la gráfica, si está en modo sincronizar
     * la gráfic con la tabla se establecen los valores de la comida en el modelo
     * de la tabla
     * @param gcce GraficaComidaChangeEvent 
     */
    @Override
    public void fireChangeEvent(GraficaComidaChangeEvent gcce) {
        //Si estamos actualizando la comida con la tabla
        if(chkSincronizarComida.isSelected()) {
            JGraficaComidaModel mGraf = modeloPoblacion.getModeloGraficaComida();
            ModeloPoblacionTabla tablaModel = 
                    modeloPoblacion.getModeloPoblacionTabla();
            
            String[] valoresComida = ModeloPoblacionFactory.
                    crearDosisComidaModeloDefecto(mGraf.getAlimentoInicial(),
                    mGraf.getAlimentoMax(), mGraf.getDiaMax(),
                    mGraf.getAlimentoFinal(), modeloPoblacion.
                    getExperimentoPadre().getNumDiasExperimento());
            //Actualizamos el modelo de la tabla con los nuevos valores
            tablaModel.setDosisComida(valoresComida);
        }
    }

    /**
     * Si cambia la población se setean en el panel para que se visualicen
     * los nuevos valores
     * @param event LogicPoblacionEvent
     */
    @Override
    public void poblacionChange(LogicPoblacionEvent event) {
        
        String fecha = modeloPoblacion.getFecha();
        
        String fechaArray[] = fecha.split("/");
        
        if(!(fechaArray[0].equals("" + calendario.getCalendar().get(Calendar.DAY_OF_MONTH))
                && fechaArray[1].equals("" + calendario.getCalendar().get(Calendar.MONTH))
                && fechaArray[2].equals("" + calendario.getCalendar().get(Calendar.YEAR)))) {
            Calendar calendar = Calendar.getInstance();
            
            calendar.set(Calendar.YEAR, Integer.parseInt(fechaArray[2]));
            calendar.set(Calendar.MONTH, Integer.parseInt(fechaArray[1]));
            calendar.set(Calendar.DAY_OF_MONTH, Integer.parseInt(fechaArray[0]));
            calendario.setCalendar(calendar);
        }
        
        //calendario;
        txtTamanioPoblacion.setText(Integer.toString(
                modeloPoblacion.getTamanioPoblacion()));
        txtTemperatura.setText(Integer.toString(
                modeloPoblacion.getTemperatura()));
        cboTemperatura.setSelectedItem(modeloPoblacion.getEscalaTemperatura());
        cboLuminosidad.setSelectedItem(modeloPoblacion.getLuminosidad());
        chkSincronizarComida.setSelected(modeloPoblacion.isSincronizarComida());
    }

    /**
     * Si cambia el idioma cambiamos los textos por el del nuevo idioma
     * @param evt LanguageEvent
     */
    @Override
    public void idiomaChange(LanguageEvent evt) {
        tabPaned.setTitleAt(0, Language.getI().getP("DATOS_POBLACION"));
        tabPaned.setTitleAt(1, Language.getI().getP("POBLACION"));
        tabPaned.setTitleAt(2, Language.getI().getP("COMENTARIOS"));

        modeloTemperatura.setItem(Language.getI().getP("CENTIGRADOS"), 0);
        modeloTemperatura.setItem(Language.getI().getP("FARENHEIT"), 1);
        cboTemperatura.removeItemListener(escuchadorTemperatura);
        if(modeloPoblacion.getEscalaTemperatura().isEmpty()) {
            cboTemperatura.setSelectedIndex(0);
        } else {
            cboTemperatura.setSelectedItem(
                Language.getI().getT(modeloPoblacion.getEscalaTemperatura()));
        }
        cboTemperatura.addItemListener(escuchadorTemperatura);
        
        if(Language.getI().getIdiomaCountry().equals("ES")) {
            jbeanComentarios.cambiarIdioma(JBeanComentarios.IDIOMA_E);
            comidaPoblacionGrafica.cambiarIdioma(JGraficaComida.IDIOMA_E);
        } else {
            jbeanComentarios.cambiarIdioma(JBeanComentarios.IDIOMA_I);
            comidaPoblacionGrafica.cambiarIdioma(JGraficaComida.IDIOMA_I);
        }
        
        
        modeloLuminosidad.setItem(Language.getI().getP("ALTA"), 0);
        modeloLuminosidad.setItem(Language.getI().getP("MEDIA"), 1);
        modeloLuminosidad.setItem(Language.getI().getP("BAJA"), 2);
        cboLuminosidad.removeItemListener(escuchadorLuminosidad);
        if(modeloPoblacion.getLuminosidad().isEmpty()) {
            cboLuminosidad.setSelectedIndex(0);
        } else {
            cboLuminosidad.setSelectedItem(
                Language.getI().getT(modeloPoblacion.getLuminosidad()));
        }
        cboLuminosidad.addItemListener(escuchadorLuminosidad);
        
        lblFechaComienzo.setText(
                Language.getI().getP("FECHA_COMIENZO_POBLACION"));
        lblTamanioPoblacion.setText(
                Language.getI().getP("TAMANIO_POBLACION_INICIAL"));
        lblTemperatura.setText(
                Language.getI().getP("TEMPERATURA"));
        lblLuminosidad.setText(
                Language.getI().getP("CONDICIONES_LUMINOSIDAD"));
        
        chkSincronizarComida.setText(
                Language.getI().getP("SINCRONIZAR_COMIDA_GRAFICA"));
        
        tablaPoblacion.getColumnModel().getColumn(0).setHeaderValue(
                Language.getI().getP("DIA"));
        tablaPoblacion.getColumnModel().getColumn(1).setHeaderValue(
                Language.getI().getP("TAMANIO_POBLACION"));
        tablaPoblacion.getColumnModel().getColumn(2).setHeaderValue(
                Language.getI().getP("BACTERIAS_MUERTAS"));
        tablaPoblacion.getColumnModel().getColumn(3).setHeaderValue(
                Language.getI().getP("TEMPERATURA"));
        tablaPoblacion.getColumnModel().getColumn(4).setHeaderValue(
                Language.getI().getP("DOSIS_COMIDA"));
    }
}
